package com.example.demo.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

/**
 * @author seabao
 * @description 日期工具类
 * @project Jasine.WADK
 * @date 2004-6-25
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);

    public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
    public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";
    public static final String DEFAULT_PATTERN_T = "yyyy-MM-dd'T'HH:mm:ss";
    public static final String DEFAULT_PATTERN_SHORT = "yyyyMMddHHmmss";
    private static ZoneId DEFAULT_ZONEID = ZoneId.systemDefault();

    private static final SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_PATTERN);
    private static final int[] TIME_FIELD_LEVELS = {Calendar.YEAR,
            Calendar.MONTH,
            Calendar.DATE,
            Calendar.HOUR_OF_DAY,
            Calendar.MINUTE,
            Calendar.SECOND,
            Calendar.MILLISECOND
    };

    /**
     * 对齐日期对象到指定精度
     *
     * @param date  日期对象
     * @param field 要对齐的时间域，参考Calendar中field的定义
     * @return 对齐后的日期
     */
    public static Date roundDate(Date date, int field) {
        if (date == null) {
            return date;
        }

        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(date.getTime());

        boolean clearFlag = false;
        for (int i = 0; i < TIME_FIELD_LEVELS.length; i++) {
            if (clearFlag) {
                cal.set(TIME_FIELD_LEVELS[i], cal.getMinimum(TIME_FIELD_LEVELS[i]));
            } else if (TIME_FIELD_LEVELS[i] == field) {
                clearFlag = true;
            }
        }

        return cal.getTime();
    }

    /**
     * 调整日期对象
     *
     * @param date   日期对象
     * @param field  时间域，参考Calendar中field的定义
     * @param amount 调整数量
     * @return 调整后的日期对象
     */
    public static Date rollDate(Date date, int field, int amount) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(date.getTime());
        cal.add(field, amount);
        return cal.getTime();
    }

    public static int getWeekDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return w;
    }

    public static String getWeekDayName(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        return weekDays[getWeekDay(date)];
    }

    /**
     * 获得日期对象的时间域值
     *
     * @param field 时间域，参考Calendar中field的定义
     * @return 对应时间域的值
     */
    public static int getDateField(Date date, int field) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(field);
    }

    /**
     * 获得修改时间域值后的日期对象
     *
     * @param date  日期对象
     * @param field 时间域，参考Calendar中field的定义
     * @param value 时间域的值
     * @return 修改后的日期对象
     */
    public static Date setDateField(Date date, int field, int value) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(date.getTime());
        cal.set(field, value);
        return cal.getTime();
    }

    public static boolean isToday(Date date) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
        calendar.setTime(date);
        if (year == calendar.get(Calendar.YEAR)
                && dayOfYear == calendar.get(Calendar.DAY_OF_YEAR))
            return true;
        else return false;
    }

    public static boolean isBoforeToday(Date date) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
        calendar.setTime(date);
        if (year > calendar.get(Calendar.YEAR)) return true;
        if (year < calendar.get(Calendar.YEAR)) return false;
        if (dayOfYear > calendar.get(Calendar.DAY_OF_YEAR)) return true;
        return false;
    }

    public static boolean isAfterToday(Date date) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
        calendar.setTime(date);
        if (year < calendar.get(Calendar.YEAR)) return true;
        if (year > calendar.get(Calendar.YEAR)) return false;
        if (dayOfYear < calendar.get(Calendar.DAY_OF_YEAR)) return true;
        return false;
    }


    /**
     * 比较天数
     *
     * @return 结束日期与开始日期天数差。大于0表示结束日期比开始日期大。 小于0表示结束日期比开始日期小
     *
     */
    public static int compareDays(Date startDay, Date endDay) {
        long start = startDay.getTime();
        long end = endDay.getTime();
        long datemills = 24L * 60L * 60L * 1000L;

        long during = end - start;

        return (int) (during / datemills);
    }


    /**
     * when btime>atime true
     *
     * @param atime
     * @param btime
     * @return
     */
    public static boolean isATimeBefaoreBTime(Date atime, Date btime) {
        boolean success = false;
        long start = atime.getTime();
        long end = btime.getTime();
        long during = end - start;
        if (during > 0 || during == 0) {
            success = true;
        }
        return success;
    }

    /**
     * 组合日期和时间
     * <p>
     *
     * @param date 时间偏移
     * @param time 日期偏移
     * @return
     */
    public static Date composeDateTime(Date date, Date time) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, getDateField(time, Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, getDateField(time, Calendar.MINUTE));
        cal.set(Calendar.SECOND, getDateField(time, Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 格式化日期
     *
     * @param date
     * @return date为空时返回空字符串
     */
    public static String dateToString(Date date) {
        if (date != null) {
            return sdf.format(date);
        }
        return "";
    }

    public static Date stringToDate(String date, String pattern) {
        Assert.notNull(date, "date string is null!");
        Assert.notNull(pattern, "pattern string is null!");

        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            Date targetDate = sdf.parse(date);
            return targetDate;
        } catch (ParseException e) {
            logger.error("日转转换失败:" + date + " " + pattern, e);
            return null;
        }
    }

    /**
     * 根据  pattern 规则格式化 日期
     *
     * @param date
     * @param pattern
     * @return date为空时返回空字符串, pattern为空时返回默认格式(" yyyy - MM - dd HH : mm : ss ")
     */
    public static String dateToString(Date date, String pattern) {
        if (!"".equals(pattern) && pattern != null) {
            SimpleDateFormat temp = new SimpleDateFormat(pattern);
            if (date != null) {
                return temp.format(date);
            }
        }
        if (date != null) {
            return sdf.format(date);
        }
        return "";
    }

    public static Date dateFormat(Date date, String pattern) throws Exception {
        if (!"".equals(pattern) && pattern != null) {
            SimpleDateFormat temp = new SimpleDateFormat(pattern);
            if (date != null) {
                String dd = temp.format(date);
                return temp.parse(dd);
            }
        }
        return null;
    }

    public static Date getDateOfBeginTime(String strDate, String pattern) {
        Date date = converToDate(strDate, pattern);
        return getStartDate(date);

    }

    public static Date getDateOfEndTime(String strDate, String pattern) {
        Date date = converToDate(strDate, pattern);
        return getEndDate(date);

    }

    public static Date getStartDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

    public static Date getEndDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    /**
     * 获取前一个月的日期
     *
     * @return 前一个月的日期
     */
    public static Date getTodayBeforeMonth(Date currentTime, String format) throws Exception {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        // Date currentTime = new Date();// 得到当前系统时间
        long now = currentTime.getTime();// 返回自 1970 年 1 月 1 日 00:00:00 GMT
        // 以来此Date 对象表示毫秒数
        currentTime = new Date(now - 86400000 * 24);
        long now1 = currentTime.getTime();
        currentTime = new Date(now1 - 86400000 * 6);
        String current = formatter.format(currentTime);
        return formatter.parse(current);
    }

    //获取整点时间
    public static LocalDateTime wholeTime() {
        LocalDateTime nowTime = LocalDateTime.now();
        LocalDateTime retTime = LocalDateTime.of(nowTime.getYear(), nowTime.getMonthValue(), nowTime.getDayOfMonth(),
                nowTime.getHour(), 0, 0);
        return retTime;
    }

    //获取零点时间
    public static LocalDateTime wholeDay() {
        LocalDateTime nowTime = LocalDateTime.now();
        LocalDateTime retTime = LocalDateTime.of(nowTime.getYear(), nowTime.getMonthValue(), nowTime.getDayOfMonth(),
                0, 0, 0);
        return retTime;
    }

    public static LocalDateTime minuteDelta(int delta) {
        LocalDateTime nowTime = LocalDateTime.now();
        return minuteDelta(nowTime, delta);
    }

    public static LocalDateTime minuteDelta(LocalDateTime time, int delta) {
        return time.plusMinutes(delta);
    }

    //当前时间的若干小时之前或之后
    public static LocalDateTime hoursDelta(int delta) {
        LocalDateTime nowTime = LocalDateTime.now();
        return hoursDelta(nowTime, delta);
    }

    //指定时间的若干小时之前或之后
    public static LocalDateTime hoursDelta(LocalDateTime time, int hoursDelta) {
        return time.plusHours(hoursDelta);

    }

    //当前时间的若干天之前或之后
    public static LocalDateTime daysDelta(int daysDelta) {
        LocalDateTime nowTime = LocalDateTime.now();
        return daysDelta(nowTime, daysDelta);
    }

    //指定时间的若干天之前或之后
    public static LocalDateTime daysDelta(LocalDateTime time, int daysDelta) {
        return time.plusDays(daysDelta);
    }


    public static boolean isToday(LocalDate date) {
        return LocalDate.now().equals(date);
    }

    public static boolean beforeToday(LocalDate date) {
        return LocalDate.now().isAfter(date);
    }

    public static boolean beforeNow(LocalDateTime datetime) {
        return LocalDateTime.now().isAfter(datetime);
    }

    public static boolean afterToday(LocalDate date) {
        return !beforeToday(date);
    }

    public static boolean afterNow(LocalDateTime datetime) {
        return !beforeNow(datetime);
    }

    public static LocalDate lastDay() {
        return LocalDate.now().minusDays(1);
    }

    public static int compareDays(LocalDate startDay, LocalDate endDay) {
        Period period = Period.between(startDay, endDay);
        return period.getDays();
    }

    public static String format() {
        return format(null, null);
    }

    public static String format(String pattern) {
        return format(null, pattern);
    }

    public static String format(LocalDateTime dateTime) {
        return format(dateTime, null);
    }

    public static String format(LocalDateTime dateTime, String pattern) {
        if (dateTime == null)
            dateTime = LocalDateTime.now();

        if (pattern == null || pattern.trim().equals(""))
            pattern = DEFAULT_PATTERN;
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern);
        return dateTime.format(fmt);
    }

    public static String formatDate(Date date, String pattern) {
        return format(toLocalDateTime(date), pattern);
    }

    public static String formatDate(Date date) {
        return format(toLocalDateTime(date), DEFAULT_PATTERN);
    }


    public static LocalDateTime converToLocalDateTime(String strDate) {
        return converToLocalDateTime(strDate, null);
    }

    public static LocalDateTime converToLocalDateTime(String strDate, String pattern) {
        if (pattern == null || pattern.trim().equals(""))
            pattern = DEFAULT_PATTERN;
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(strDate, fmt);
    }

    public static Date converToDate(String strDate, String pattern) {
        LocalDateTime localDateTime = converToLocalDateTime(strDate, pattern);
        return toDate(localDateTime);
    }

    /**
     * 把java.util.Date转化为java.time.LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate toLocalDate(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(DEFAULT_ZONEID).toLocalDate();
    }

    /**
     * 把java.util.Date转化为java.time.LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(DEFAULT_ZONEID).toLocalDateTime();
    }

    //   LocalDateTime <---> ZoneDateTime <--->  Instant <---> Date
    public static Date toDate(LocalDateTime localDateTime) {
        Instant instant = localDateTime.atZone(DEFAULT_ZONEID).toInstant();
        return Date.from(instant);
    }

    public static Date epochMilli2Date(long epochMilli) {
        Instant instant = Instant.ofEpochMilli(epochMilli);
        return Date.from(instant);
    }

    public static LocalDateTime fromEpochMilli(long epochMilli) {
        Instant instant = Instant.ofEpochMilli(epochMilli);
        return instant.atZone(DEFAULT_ZONEID).toLocalDateTime();
    }

    public static String convertFormat(String srcDate, String srcPattern, String tgtPattern) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(srcPattern);
        LocalDateTime l = LocalDateTime.parse(srcDate, df);
        df = DateTimeFormatter.ofPattern(tgtPattern);
        return df.format(l);

    }

    public static void main(String[] args) throws Exception {
        Date date = DateUtils.parseDate("2014-02-16", "yyyy-MM-dd");
        System.out.println(dateToString(date, "yyyy-MM-dd"));
    }


}